package com.rankeiot.platform.service;

import com.rankeiot.core.Context;
import com.rankeiot.core.data.ValHolder;
import com.rankeiot.core.util.StringUtil;
import lombok.RequiredArgsConstructor;
import org.sagacity.sqltoy.callback.UpdateRowHandler;
import org.sagacity.sqltoy.dao.SqlToyLazyDao;
import org.sagacity.sqltoy.model.QueryExecutor;
import org.sagacity.sqltoy.plugins.id.IdGenerator;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.function.BiConsumer;

public class SequenceIdGenerator implements IdGenerator {
    private static SqlToyLazyDao _dao;
    private static synchronized SqlToyLazyDao getDao(){
        if(_dao==null){
            _dao= Context.getBean(SqlToyLazyDao.class);
        }
        return _dao;
    }
    /**
     * @todo <b>返回id</b>
     * @param tableName       为特殊的主键生成策略预留表名
     * @param signature       识别符号
     * @param relatedColValue 关联字段的值
     * @param bizDate         当前日期
     * @param idType      主键数据类型
     * @param length          主键长度
     * @param sequencSize     流水号长度,如:20210709[001] 后三位为流水
     * @return
     */
    @Override
    public Object getId(String tableName, String signature, String[] relatedColumns, Object[] relatedColValue, Date bizDate, String idType, int length, int sequencSize) {
        String key=tableName;
        if(StringUtil.isNotEmpty(signature)){
           key += "_"+signature;
        }
        if (org.sagacity.sqltoy.utils.StringUtil.isBlank(idType)) {
            return getMaxNoStr(key,length);
        }
        // 按照优先顺序对比
        if ("java.lang.string".equals(idType)) {
            return getMaxNoStr(key,length);
        }
        if ("java.lang.integer".equals(idType)) {
            return getMaxNo(key).intValue();
        }
        if ("java.lang.long".equals(idType)) {
            return getMaxNo(key);
        }
        if ("java.math.biginteger".equals(idType)) {
            return new BigInteger(getMaxNo(key)+"");
        }
        if ("java.math.bigdecimal".equals(idType)) {
            return new BigDecimal(getMaxNo(key)+"");
        }
        if ("long".equals(idType)) {
            return getMaxNo(key).longValue();
        }
        if ("int".equals(idType)) {
            return getMaxNo(key).intValue();
        }
        if ("java.lang.short".equals(idType)) {
            return getMaxNo(key).shortValue();
        }
        if ("short".equals(idType)) {
            return getMaxNo(key).shortValue();
        }
        return null;
    }

    public static Long getMaxNo(String key){
        return getMaxNo(key,1);
    }
    public static String getMaxNoStr(String key,int length){
        length=Math.max(0,length);
        return StringUtil.leftPad(Long.toString(getMaxNo(key),Character.MAX_RADIX).toUpperCase(),'0',length);
    }

    /**
     * 获取一批ID
     * @param key
     * @param batch
     * @return
     */
    private static long getMaxNo(String key,int batch){
        SqlToyLazyDao dao=getDao();
       // dao.updateFetch()
        //sequence_name,current_value,increment
        QueryExecutor qe=new QueryExecutor("select no_name,no_value from t_max_no where no_name=?");
        qe.values(key);
        ValHolder<Long> vh=new ValHolder<>(-1L);
        UpdateRowHandler ur=new MaxNoBatchUpdateHandler(vh,batch);
        dao.updateFetch(qe,ur);
//        dao.updateFetch(qe,(rs, index) -> {
//
//           long id= rs.getLong("no_value");
//           rs.updateLong("no_value",id+batch);
//           vh.value=id;
//        });
        //序号从1开始
        if(vh.value==-1L){
            Map v=new HashMap();
            v.put("name",key);
            v.put("value",batch+1);
            dao.executeSql("insert into t_max_no(no_name,no_value) values(:name,:value)", v);
            return 1L;
        }
        return vh.value;
    }
    public static BatchSequence getBatchNo(String key,int batch){
        return new BatchSequence(key,batch);
    }

    @RequiredArgsConstructor
    private static class MaxNoBatchUpdateHandler implements UpdateRowHandler{
        private final ValHolder valHolder;
        private final int batch;

        public void updateRow(ResultSet rs, int index) throws Exception {
            long id= rs.getLong("no_value");
            rs.updateLong("no_value",id+batch);
            valHolder.value=id;
        }
    }
    public static class BatchSequence{
        private String key;
        private long current=0;
        private long max=0;
        private int batch;
        BatchSequence(String key,int batch){
            this.key=key;
            this.batch=batch;
        }
        public synchronized long next(){
            if(current==max){
              current=getMaxNo(key,batch);
              max=current+batch;
            }
            return current++;
        }
        public String next(int idLength){
            return StringUtil.leftPad(next()+"",'0',idLength);
        }
        public String nextShort(int idLength){
            return StringUtil.leftPad(Long.toString(next(),Character.MAX_RADIX),'0',idLength);
        }
    }
}
